In this report I use syuzhet R package to conduct analysis of one of my favourite books - Fyodor Dostoyevsky’s The Idiot. We explore syuzhet package capabilites to see how sentiments change throughout the book. We compare different method of measuring sentiment and visualising it. Next we compare The Idiot with other works of Fyodor Dostoyevsky. Finally we do similar comparison with works of Leo Tolstoy, another great russian writer from the same epoch.
#devtools::install_github("mjockers/syuzhet")
Sys.setenv(JAVA_HOME="/Library/Java/JavaVirtualMachines/jdk1.8.0_20.jdk/Contents/Home")
library(syuzhet)
library(tidyverse)
Loading tidyverse: ggplot2
Loading tidyverse: tibble
Loading tidyverse: tidyr
Loading tidyverse: readr
Loading tidyverse: purrr
Loading tidyverse: dplyr
Conflicts with tidy packages ------------------------------------------------------------------
filter(): dplyr, stats
lag(): dplyr, stats
library(gutenbergr)
library(forcats)
library(ggthemes)
library(viridis)
Loading required package: viridisLite
We will use Gutenberg Project Library to get the text. First let’s examine which work of Dostoyevsky we have available. We use gutenbergr R package.
dostoyevsky <- gutenberg_authors %>% filter(author == "Dostoyevsky, Fyodor")
We focus on work which I remeber well - The Idiot.
(idiot_gutenberger_entry <- gutenberg_works(author == "Dostoyevsky, Fyodor", language == "en", title == "The Idiot"))
First we check the format, and see if text was downloaded correctly.
idiot <- gutenberg_download(idiot_gutenberger_entry["gutenberg_id"])
Determining mirror for Project Gutenberg from http://www.gutenberg.org/robot/harvest
Using mirror http://aleph.gutenberg.org
head(idiot)
The Idiot constitutes of 4 parts. As the work is long (Mordern Library edition has 667 pages), we will split into part for sake of visualisation. First we extract the sentences from the text using get_sentences method from syuzhet. Next we find where different parts of the book begin.
idiot_v <- get_sentences(idiot$text)
part_1_start = grep("PART I", idiot_v)[1]
part_2_start = grep("PART II", idiot_v)[1]
part_3_start = grep("PART III", idiot_v)[1]
part_4_start = grep("PART IV", idiot_v)[1]
We evaluate emotional valence on each sentence using 4 methods available in Syuzhet - defualt(syuzhet), bing, afinn and nrc. Additionally we also extract different sentiment from nrc lexicon.
linenumber = seq_along(idiot_v)
syuzhet_vector <- get_sentiment(idiot_v, method="syuzhet")
bing_vector <- get_sentiment(idiot_v, method="bing")
afinn_vector <- get_sentiment(idiot_v, method="afinn")
nrc_vector <- get_sentiment(idiot_v, method="nrc")
nrc_sentiment <- get_nrc_sentiment(idiot_v)
idiot_sentiment <- cbind(
tibble(linenumber = linenumber,
text = idiot_v,
syuzhet_emotional_valence = syuzhet_vector,
bing_emotional_valence = bing_vector,
afinn_emotional_valence = afinn_vector,
nrc_emotional_valence = nrc_vector),
nrc_sentiment)
head(idiot_sentiment)
We annotate different parts of the book and provide additional numering for each part to make visualisation of results easier.
idiot_sentiment["part"] = "PART I"
idiot_sentiment[part_2_start:part_3_start, "part"] = "PART II"
idiot_sentiment[part_3_start:part_4_start, "part"] = "PART III"
idiot_sentiment[part_4_start:dim(idiot_sentiment)[1], "part"] = "PART IV"
idiot_sentiment$part = as.factor(idiot_sentiment$part)
idiot_sentiment[idiot_sentiment$part == "PART I", "part_linenumber"] = seq_along(1:(part_2_start - 1))
idiot_sentiment[idiot_sentiment$part == "PART II", "part_linenumber"] = seq_along(part_2_start:(part_3_start-1))
idiot_sentiment[idiot_sentiment$part == "PART III", "part_linenumber"] = seq_along(part_3_start:(part_4_start-1))
idiot_sentiment[idiot_sentiment$part == "PART IV", "part_linenumber"] = seq_along(part_4_start:dim(idiot_sentiment)[1])
#head(idiot_sentiment$part)
#tail(idiot_sentiment$part)
theme_syuzhet <- #theme_tufte() +
theme(axis.ticks =element_line()) +
theme(axis.text =element_text(size=6)) +
theme(panel.border=element_blank()) +
theme(legend.title=element_text(size=6)) +
theme(legend.title.align=1) +
theme(legend.text=element_text(size=6)) +
theme(legend.position="bottom") +
theme(legend.key.size=unit(0.2, "cm")) +
theme(legend.key.width=unit(1, "cm"))
theme_syuzhet_no_x_axis <- theme_syuzhet +
theme(axis.ticks=element_blank(), axis.text.x=element_blank())
Finally we can plot extracted sentiment. We use different colours for different sentiment extraction method.
idiot_sentiment_by_method <- idiot_sentiment %>%
select(linenumber, part_linenumber, part,
syuzhet_emotional_valence,
bing_emotional_valence,
afinn_emotional_valence,
nrc_emotional_valence) %>%
gather(method, emotional_valence, syuzhet_emotional_valence : nrc_emotional_valence)
ggplot(idiot_sentiment_by_method, aes(x = part_linenumber, y = emotional_valence, color = method)) +
geom_point(alpha = 0.4, size = 0.5) +
facet_wrap(~part, nrow = 4) +
theme_syuzhet +
labs(y="Sentiment Score", x="Narrative Lenght", title = expression(paste("Emotional Valence in ", italic("The Idiot"))))

These plots need zooming to be reabable, but we can see that scales used by different methods are slightly different and some of them give only discrete values. Definately plotting these as point plots might not the best idea, let’s try line plot instead.
ggplot(idiot_sentiment_by_method, aes(x = part_linenumber, y = emotional_valence, color = method)) +
geom_line(alpha = 0.5) +
facet_wrap(~part, nrow = 4) +
theme_syuzhet +
labs(y="Sentiment Score", x="Narrative Lenght", title = expression(paste("Emotional Valence in ", italic("The Idiot"))))

With lineplots we start two notice better general variability of emotional valance, and some extreme points. We will examine these extreme points now to get better intutions about numbers we are obtaining. We zoom in a bit at points with strongest negative emotions.
idiot_sentiment_by_method %>% filter(linenumber > 300, linenumber < 500) %>%
ggplot( aes(x = linenumber, y = emotional_valence, color = method)) +
geom_line(alpha = 0.5) +
theme_syuzhet +
labs(y="Sentiment Score", x="Narrative Lenght", title = expression(paste("Emotional Valence in ", italic("The Idiot")," - lines 300 - 500")))

idiot_sentiment %>% filter(linenumber >= 405, linenumber < 415)
Seems like line 406 is the most negative one.
idiot_sentiment %>% filter(linenumber == 406) %>% select(text)
This surely sounds negative - lets see what other emotions it conveys.
emotions <- c("anger", "anticipation", "disgust", "fear",
"joy", "sadness", "surprise", "trust")
idiot_sentiment %>% filter(linenumber == 406) %>% select(one_of(emotions))
Emotions captured in the sentence obviously depend on larger context, but judging by sentence itself, authomatically recognized emotions are quite accurate. Let’s look at another low point - around line number 10000.
idiot_sentiment_by_method %>% filter(linenumber > 10000, linenumber < 10100) %>%
ggplot( aes(x = linenumber, y = emotional_valence, color = method)) +
geom_line(alpha = 0.5) +
theme_syuzhet +
labs(y="Sentiment Score", x="Narrative Lenght", title = expression(paste("Emotional Valence in ", italic("The Idiot")," - lines 10000 - 10100")))

idiot_sentiment %>% filter(linenumber >= 10025, linenumber < 10035)
This time line 10030 is the most negative.
idiot_sentiment %>% filter(linenumber == 10030) %>% select(text)
idiot_sentiment %>% filter(linenumber == 10030) %>% select(one_of(emotions))
Again - it seems that our method might be off, but again reasonably so.
Having better understanding and some proof of accuracy of obtained scores let’s come back to our comparison. Let’s try plotting smoothed values for different scoring methods.
ggplot(idiot_sentiment_by_method, aes(x = part_linenumber, y = emotional_valence, color = method)) +
geom_smooth(alpha = 0.5, se= FALSE) +
facet_wrap(~part, nrow = 4) +
theme_syuzhet +
labs(y="Sentiment Score", x="Narrative Lenght", title = expression(paste("Emotional Valence in ", italic("The Idiot")," - smoothed")))

Plot presents smoothed sentiments comuted with different methods. Smoothing is done by fitting GAM(Generalized Additive Model) to the data, curve is approximated by spline. We see that all curves share the same basic shape. For the further analysis we will use Syuzhet default sentiment valence estimation method. Rest of the sentiments will be measured with NRC method.
First let’s again look at the plot. This time instead of ggplot we use plotting capabilities of Syuzhet. Shape is different here, as we use single curve for the whole novel, and we use different smothing method. General shape of the curve seems to be acurrately representing the novel. At the beginning of the novel there are many postive emotions which go steadily more negative until the middle of first part. From this point sentimnt is oscilating but stays on the negative side. Finally we reach the lowest point around line 10000 - 11000. This is the point round the end of part 3 and beggining of part 4. From this point emotion steadily rise util the ending which is again on the sad note. This reflects event in the novel well, althought some of the plots - e.g. simplified macro shape don’t capture dip at the end of the novel.
simple_plot(idiot_sentiment$syuzhet_emotional_valence)

Now let’s inspect how different emotions appear in the novel.
emotions <- idiot_sentiment %>% select(linenumber, part, part_linenumber, anger, anticipation,
disgust, fear, joy, sadness, surprise,
trust) %>%
gather(sentiment, value, anger:trust)
Error in idiot_sentiment %>% select(linenumber, part, part_linenumber, :
could not find function "%>%"
emotions %>%
ggplot(aes(x = part_linenumber, y = sentiment, fill = value)) +
geom_tile(width = 3) +
facet_wrap(~part, nrow = 4) +
scale_fill_viridis(name="Sentiment\nScore") +
labs(x=NULL, y=NULL, title=expression(paste("Sentiment in ", italic("The Idiot")))) +
theme_tufte() +
theme_syuzhet +
scale_x_discrete(expand=c(0,0))

On the plot we negative emotion in the higher parts of the stripe and positive ones in the lower part. In general we see that sentiment score stays low most of the time, but there are particular episodes(in particular in fist part) with stronger negative and positive emotions. Now let’s try making use of more complex functionalities of Syuzhet.
gutenberg_sentiments <- function(work) {
sentence_v <- get_sentences(work$text)
linenumber <- seq_along(sentence_v)
emotional_valence <- get_sentiment(sentence_v, method="syuzhet")
nrc_sentiment <- get_nrc_sentiment(sentence_v)
cbind(
tibble(linenumber = linenumber,
text = sentence_v,
emotional_valence = emotional_valence),
nrc_sentiment)
}
sentiment_tranformed <- function(sentiment,
columns,
func = get_dct_transform) {
transformed_list <- columns %>% map(~ func(sentiment[,.x]))
names(transformed_list) <- columns
transformed_list[["index"]] <- seq_along(transformed_list[[1]])
as.tibble(transformed_list)
}
emotion_columns = c("joy","trust","anticipation","surprise","sadness","disgust","fear","anger")
valence_and_emotions = c("emotional_valence", emotion_columns)
emotional_summary <- function(sentiment) {
colSums(prop.table(sentiment[,emotion_columns]))
}
idiot_sentiment["emotional_valence"] <- idiot_sentiment["syuzhet_emotional_valence"]
idiot_dct_tranformed <- sentiment_tranformed(idiot_sentiment, valence_and_emotions)
idiot_fourier_transformed <- sentiment_tranformed(idiot_sentiment, valence_and_emotions, get_transformed_values)
Syuzhet have two methods of creating curves aproximating “emotional shape” of the novel - by Fourier transform with low pass filter and by Discrete Cosine Transport(dct). We inspect both methods.
idiot_dct_tranformed["method"] <- "dct"
idiot_fourier_transformed["method"] <- "fourier"
idiot_fourier_transformed %>% gather(sentiment, value, joy:anger) %>%
ggplot(aes(x = index, y = value, color = sentiment)) +
labs(y="Sentiment Score", x="Normalized Narrative Length") +
geom_line() +
theme_syuzhet

First let’s see effect of using Fourier transform to get smoother version of sentiment curves for The Idiot. We see artifacts at the beginning and at the end of the novel. They are due to periodicity of fourier functions. This problem was noticed by authors and others https://annieswafford.wordpress.com/2015/03/30/why-syuzhet-doesnt-work-and-how-we-know/ nd other http://www.matthewjockers.net/ . This is why currently author recommends using other method. Still plot gives us idea which emotiona are most strongly expressed through the narratve. We see that all emotions have similar base shape, but slightly different levels.
idiot_dct_tranformed %>% gather(sentiment, value, joy:anger) %>%
ggplot(aes(x = index, y = value, color = sentiment)) + geom_line() + theme_syuzhet

DCT tranfrom gives slightly different picture. Artifical dips at the beggining and at the end of the novel and not present anymore. We see that trust, anticipation and joy and surprise oscilating through the narrative time, starting high, and having two low points around 1/4-th and 3/4th of the narrive time, while negative emotions like anger, sadness and disgust start on the lower point and slowly raise, until the highest point which happens after the half of the novel(later for disgust). From this point they lower slighly until the end of the novel. Having well annotated novel could allow us to connect certain sentiments to specific moment in the narrative. At the current moment conducting such analysis is rather hard, nor long and complex novel like The Idiot and requires very good knowlegde of the text.
Although trasnformations are usefull in conducting analysis of general theme of the text, i believe one of it’s main advantedeg is it’s normalizing effet which allows ust to compare different texts. To explore this possibility I conduct simple analysis of emotional valence and expressed sentiment in the most famous works of Fyodor Dostoyevsky and Leo Tolstoy.
gutenberg_works(author == "Dostoyevsky, Fyodor", language == "en")
notes_from_underground <- gutenberg_download(600)
gambler <-gutenberg_download(2197)
crime_and_punishment <- gutenberg_download(2554)
brothers_karamazov <- gutenberg_download(28054)
white_nights <- gutenberg_download(36034)
gutenberg_works(author == "Tolstoy, Leo, graf", language == "en")
#father_sergius <- gutenberg_download(985)
war_and_peace <- gutenberg_download(2600)
master_and_man <- gutenberg_download(986)
anna_karenina <- gutenberg_download(1399)
resurrection <- gutenberg_download(1938)
I use Project Guteberg again for this aim. I take 6 works from Fyodor Dostoyevsky - Notes from the Underground, Gambler, White Nights, Crime and Punishment, Idiot and Brothers Karamazov. I wanted to incude both 3 ‘greatest’ works of Dostoyevsky as well as some acclaimed shorter works. Similarly for Leo Toylsto I analyze his 2 most famoust works Anna Karenina and War and Peace, and two of the later work - Master and Man and Resurrection.
author_sentiments <- function(works) {
works %>%
map(gutenberg_sentiments)
}
author_emotional_summary <- function(works) {
works %>%
map(~emotional_summary(gutenberg_sentiments(.x))) %>%
map2(names(works), ~ c(.x, title = .y)) %>%
reduce(rbind)
}
author_valence <- function(works) {
works %>%
map(~ sentiment_tranformed(gutenberg_sentiments(.x), c("emotional_valence"))) %>%
map2_df(names(works), ~ mutate(.x, title = .y))
}
tolstoy_works <- list(war_and_peace, anna_karenina, master_and_man, resurrection)
names(tolstoy_works) <- c("War and Peace", "Anna Karenina","Master and Man", "Resurrection")
tolstoy_emotional_valence <- author_valence(tolstoy_works)
tolstoy_emotional_summary <- author_emotional_summary(tolstoy_works)
dostoyevsky_works <- list(white_nights, notes_from_underground, gambler, crime_and_punishment, idiot, brothers_karamazov)
names(dostoyevsky_works) <- c("White Nights", "Notes from the underground", "Gambler", "Crime and Punishment", "The Idiot", "Brothers Karamazov")
dostoyevsky_emotional_valence <- author_valence(dostoyevsky_works)
dostoyevsky_emotional_summary <- author_emotional_summary(dostoyevsky_works)
View(hours_data)
First we look at emotional valence in the works of Dostoyevsky.
dostoyevsky_emotional_valence %>%
ggplot(aes(x = index, y = emotional_valence, color = title)) +
geom_line() +
theme_syuzhet +
labs(y="Emotional Valence", x="Normalized Narrative Length")

NA
It seems that Idiot is quite an unsual works for Dostoyevsky, it is much more positive than his other works. We see that most of the works either oscilate between positive and negative emotiona , and largly negative. We see also that shapes differ quite singificantly between different text, nd there doesn’t seem to be Dostoyesky formula for a novel. To get better perspective let’s now take a look at works of the other great russian writer from the 19th century - Leo Tolstoy.
tolstoy_emotional_valence %>%
ggplot(aes(x = index, y = emotional_valence, color = title)) +
geom_line() +
theme_syuzhet +
labs(y="Emotional Valence", x="Normalized Narrative Length")

One common theme of Tolstoy’s works is that the thye containe more positive emotions and his most famoust works “Anna Karenina” and War and Peace have their emotional valence higher than later work.
tolstoy_emotional_valence["author"] = "Tolstoy, Leo"
dostoyevsky_emotional_valence["author"] = "Dostoyevsky, Fyodor"
rbind(tolstoy_emotional_valence,dostoyevsky_emotional_valence) %>%
ggplot(aes(x = index, y = emotional_valence, color = title, linetype = author)) +
geom_line() +
#theme_syuzhet +
labs(y="Emotional Valence", x="Normalized Narrative Length")

When we compare both writers we see that Tolstoy works are much stronger in postive emotions than works of Dostoyevsky. The Idiot is quite outstanding, compared to other Dostoyevsky works, and actually is closer to works of Toystoy thank other works of Dostoyevsky in terms of emotional valence. One interesting observation is that works which are considered the greatest for both authors have also biggest changes in emotional valence.
tolstoy_emotional_valence["author"] <- "Tolstoy, Leo"
dostoyevsky_emotional_valence["author"] <- "Dostoyevsky, Fyodor"
rbind(tolstoy_emotional_valence,dostoyevsky_emotional_valence) %>%
filter(title %in% c("Anna Karenina", "War and Peace", "The Idiot", "Brothers Karamazov", "Crime and Punishment")) %>%
ggplot(aes(x = index, y = emotional_valence, color = title, linetype = author)) + geom_line()
Let’s look at perspecitive of distinct emotions in the works:
row.names(dostoyevsky_emotional_summary) <- 1:6
dostoyevsky_emotional_summary_df <- as.data.frame(dostoyevsky_emotional_summary)
dostoyevsky_emotional_summary_df["author"] <- "Dostoyevsky, Fyodor"
row.names(tolstoy_emotional_summary) <- 1:4
tolstoy_emotional_summary_df <- as.data.frame(tolstoy_emotional_summary)
tolstoy_emotional_summary_df["author"] <- "Tolstoy, Leo"
emotional_summary_df <- rbind(dostoyevsky_emotional_summary_df, tolstoy_emotional_summary_df) %>% gather(emotion, value, joy:anger)
emotional_summary_df["emotion"] <- fct_relevel(as_factor(emotional_summary_df[,"emotion"]), c("joy","trust","anticipation","surprise","sadness","disgust","fear","anger"))
ggplot(emotional_summary_df, aes(x = title, y = value, fill = emotion)) +
geom_col(position = position_dodge()) +
coord_flip() +
scale_color_brewer(2) +
theme(axis.ticks=element_blank(), axis.text.x=element_blank()) +
facet_wrap(~author, scales = "free_y")

First we notice for both authors is that universally strongest emotion are trust and anticipation. With information we have it is hard to judge if this is some charateristic of work, or maybe it is caused by some flaw in analysis method. To evalute it properly we should conduct proper analysis of the bigger corpora of works from the period. Some impressions one could take is that negative emotions are more common in works of Dostoyevsky than in writing of Tolstoy. In Crime and Punishment and Brothers Karamazov, and in Notes fom the Underground fear is one of the dominating emotions. The Idiot seems to be most positive of Dostoyevsky works from the one we examined. When examining works of Tolstoy we see that some later work like Master and Man and Resurection contains more negative emotions, while in both Anna Karenina and War and Peace joy is one of the most common sentiments. Still we should treat this analysis as tool for hypothesis generation.
Syuzhet is fantastic tool. I makes sentiment analysis easy and pleasant. I found it particular useful for exploratory analysis and hypothesis generation of longer textual data. Still there is a number of hyperparametrs we have to tune to use, we have to choose the right lexicon and sentiment analysis method and it is not clear which methods of smoothing work best. Most of existing benchmarks for sentiment analysis are done for differnt kinds of texts - e.g. movie reviews and therefore are not always applicable for corpora of fiction, which often uses very specific, older language. To evaluate it properly it would be great to have bigger, sentiment annotated corpora of literature.
LS0tCnRpdGxlOiAiU2VudGltZW50IGFuYWx5c2lzIG9mIEZ5b2RvciBEb3N0b3lldnNreSdzIFRoZSBJZGlvdCBhbmQgY29tcGFyaXNvbiB3aXRoIG90aGVyIHdvcmtzIgpvdXRwdXQ6CiAgcGRmX2RvY3VtZW50OiBkZWZhdWx0CiAgaHRtbF9ub3RlYm9vazogZGVmYXVsdAogIGh0bWxfZG9jdW1lbnQ6IGRlZmF1bHQKLS0tCkluIHRoaXMgcmVwb3J0IEkgdXNlIHN5dXpoZXQgUiBwYWNrYWdlIHRvIGNvbmR1Y3QgYW5hbHlzaXMgb2Ygb25lIG9mIG15IGZhdm91cml0ZSBib29rcyAtIEZ5b2RvciBEb3N0b3lldnNreSdzIFRoZSBJZGlvdC4gV2UgZXhwbG9yZSBzeXV6aGV0IHBhY2thZ2UgY2FwYWJpbGl0ZXMgdG8gc2VlIGhvdyBzZW50aW1lbnRzIGNoYW5nZSB0aHJvdWdob3V0IHRoZSBib29rLiBXZSBjb21wYXJlIGRpZmZlcmVudCBtZXRob2Qgb2YgbWVhc3VyaW5nIHNlbnRpbWVudCBhbmQgdmlzdWFsaXNpbmcgaXQuIE5leHQgd2UgY29tcGFyZSBUaGUgSWRpb3Qgd2l0aCBvdGhlciB3b3JrcyBvZiBGeW9kb3IgRG9zdG95ZXZza3kuIEZpbmFsbHkgd2UgZG8gc2ltaWxhciBjb21wYXJpc29uIHdpdGggd29ya3Mgb2YgTGVvIFRvbHN0b3ksIGFub3RoZXIgZ3JlYXQgcnVzc2lhbiB3cml0ZXIgZnJvbSB0aGUgc2FtZSBlcG9jaC4KCmBgYHtyIHdhcm5pbmc9RkFMU0V9CiNkZXZ0b29sczo6aW5zdGFsbF9naXRodWIoIm1qb2NrZXJzL3N5dXpoZXQiKQpTeXMuc2V0ZW52KEpBVkFfSE9NRT0iL0xpYnJhcnkvSmF2YS9KYXZhVmlydHVhbE1hY2hpbmVzL2pkazEuOC4wXzIwLmpkay9Db250ZW50cy9Ib21lIikKbGlicmFyeShzeXV6aGV0KQpsaWJyYXJ5KHRpZHl2ZXJzZSkKbGlicmFyeShndXRlbmJlcmdyKQpsaWJyYXJ5KGZvcmNhdHMpCmxpYnJhcnkoZ2d0aGVtZXMpCmxpYnJhcnkodmlyaWRpcykKYGBgCldlIHdpbGwgdXNlIEd1dGVuYmVyZyBQcm9qZWN0IExpYnJhcnkgdG8gZ2V0IHRoZSB0ZXh0LiBGaXJzdCBsZXQncyBleGFtaW5lIHdoaWNoIHdvcmsgb2YgRG9zdG95ZXZza3kgd2UgaGF2ZSBhdmFpbGFibGUuIFdlIHVzZSBndXRlbmJlcmdyIFIgcGFja2FnZS4KYGBge3J9CmRvc3RveWV2c2t5IDwtIGd1dGVuYmVyZ19hdXRob3JzICU+JSBmaWx0ZXIoYXV0aG9yID09ICJEb3N0b3lldnNreSwgRnlvZG9yIikgCmBgYApXZSBmb2N1cyBvbiB3b3JrIHdoaWNoIEkgcmVtZWJlciB3ZWxsIC0gVGhlIElkaW90LgpgYGB7cn0KKGlkaW90X2d1dGVuYmVyZ2VyX2VudHJ5IDwtIGd1dGVuYmVyZ193b3JrcyhhdXRob3IgPT0gIkRvc3RveWV2c2t5LCBGeW9kb3IiLCBsYW5ndWFnZSA9PSAiZW4iLCB0aXRsZSA9PSAiVGhlIElkaW90IikpCmBgYApGaXJzdCB3ZSBjaGVjayB0aGUgZm9ybWF0LCBhbmQgc2VlIGlmIHRleHQgd2FzIGRvd25sb2FkZWQgY29ycmVjdGx5LiAKYGBge3J9CmlkaW90IDwtIGd1dGVuYmVyZ19kb3dubG9hZChpZGlvdF9ndXRlbmJlcmdlcl9lbnRyeVsiZ3V0ZW5iZXJnX2lkIl0pCmhlYWQoaWRpb3QpCmBgYApUaGUgSWRpb3QgY29uc3RpdHV0ZXMgb2YgNCBwYXJ0cy4gQXMgdGhlIHdvcmsgaXMgbG9uZyAoTW9yZGVybiBMaWJyYXJ5IGVkaXRpb24gaGFzIDY2NyBwYWdlcyksIHdlIHdpbGwgc3BsaXQgaW50byBwYXJ0IGZvciBzYWtlIG9mIHZpc3VhbGlzYXRpb24uIEZpcnN0IHdlIGV4dHJhY3QgdGhlIHNlbnRlbmNlcyBmcm9tIHRoZSB0ZXh0IHVzaW5nIGdldF9zZW50ZW5jZXMgbWV0aG9kIGZyb20gc3l1emhldC4gTmV4dCB3ZSBmaW5kIHdoZXJlIGRpZmZlcmVudCBwYXJ0cyBvZiB0aGUgYm9vayBiZWdpbi4KYGBge3J9CmlkaW90X3YgPC0gZ2V0X3NlbnRlbmNlcyhpZGlvdCR0ZXh0KQpwYXJ0XzFfc3RhcnQgPSBncmVwKCJQQVJUIEkiLCBpZGlvdF92KVsxXQpwYXJ0XzJfc3RhcnQgPSBncmVwKCJQQVJUIElJIiwgaWRpb3RfdilbMV0KcGFydF8zX3N0YXJ0ID0gZ3JlcCgiUEFSVCBJSUkiLCBpZGlvdF92KVsxXQpwYXJ0XzRfc3RhcnQgPSBncmVwKCJQQVJUIElWIiwgaWRpb3RfdilbMV0KYGBgCgpXZSBldmFsdWF0ZSBlbW90aW9uYWwgdmFsZW5jZSBvbiBlYWNoIHNlbnRlbmNlIHVzaW5nIDQgbWV0aG9kcyBhdmFpbGFibGUgaW4gU3l1emhldCAtIGRlZnVhbHQoc3l1emhldCksIGJpbmcsIGFmaW5uIGFuZCBucmMuIEFkZGl0aW9uYWxseSB3ZSBhbHNvIGV4dHJhY3QgZGlmZmVyZW50IHNlbnRpbWVudCBmcm9tIG5yYyBsZXhpY29uLgpgYGB7cn0KbGluZW51bWJlciA9IHNlcV9hbG9uZyhpZGlvdF92KQpzeXV6aGV0X3ZlY3RvciA8LSBnZXRfc2VudGltZW50KGlkaW90X3YsIG1ldGhvZD0ic3l1emhldCIpCmJpbmdfdmVjdG9yIDwtIGdldF9zZW50aW1lbnQoaWRpb3RfdiwgbWV0aG9kPSJiaW5nIikKYWZpbm5fdmVjdG9yIDwtIGdldF9zZW50aW1lbnQoaWRpb3RfdiwgbWV0aG9kPSJhZmlubiIpCm5yY192ZWN0b3IgPC0gZ2V0X3NlbnRpbWVudChpZGlvdF92LCBtZXRob2Q9Im5yYyIpCm5yY19zZW50aW1lbnQgPC0gZ2V0X25yY19zZW50aW1lbnQoaWRpb3RfdikKCmlkaW90X3NlbnRpbWVudCA8LSBjYmluZCgKICAgICAgICAgICAgICAgICAgICB0aWJibGUobGluZW51bWJlciA9IGxpbmVudW1iZXIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgIHRleHQgPSBpZGlvdF92LAogICAgICAgICAgICAgICAgICAgICAgICAgICBzeXV6aGV0X2Vtb3Rpb25hbF92YWxlbmNlID0gc3l1emhldF92ZWN0b3IsCiAgICAgICAgICAgICAgICAgICAgICAgICAgIGJpbmdfZW1vdGlvbmFsX3ZhbGVuY2UgPSBiaW5nX3ZlY3RvciwKICAgICAgICAgICAgICAgICAgICAgICAgICAgYWZpbm5fZW1vdGlvbmFsX3ZhbGVuY2UgPSBhZmlubl92ZWN0b3IsCiAgICAgICAgICAgICAgICAgICAgICAgICAgIG5yY19lbW90aW9uYWxfdmFsZW5jZSA9IG5yY192ZWN0b3IpLAogICAgICAgICAgICAgICAgICAgIG5yY19zZW50aW1lbnQpCmhlYWQoaWRpb3Rfc2VudGltZW50KQpgYGAKV2UgYW5ub3RhdGUgZGlmZmVyZW50IHBhcnRzIG9mIHRoZSBib29rIGFuZCBwcm92aWRlIGFkZGl0aW9uYWwgbnVtZXJpbmcgZm9yIGVhY2ggcGFydCB0byBtYWtlIHZpc3VhbGlzYXRpb24gb2YgcmVzdWx0cyBlYXNpZXIuCgpgYGB7cn0KaWRpb3Rfc2VudGltZW50WyJwYXJ0Il0gPSAiUEFSVCBJIgppZGlvdF9zZW50aW1lbnRbcGFydF8yX3N0YXJ0OnBhcnRfM19zdGFydCwgInBhcnQiXSA9ICJQQVJUIElJIgppZGlvdF9zZW50aW1lbnRbcGFydF8zX3N0YXJ0OnBhcnRfNF9zdGFydCwgInBhcnQiXSA9ICJQQVJUIElJSSIKaWRpb3Rfc2VudGltZW50W3BhcnRfNF9zdGFydDpkaW0oaWRpb3Rfc2VudGltZW50KVsxXSwgInBhcnQiXSA9ICJQQVJUIElWIgppZGlvdF9zZW50aW1lbnQkcGFydCA9IGFzLmZhY3RvcihpZGlvdF9zZW50aW1lbnQkcGFydCkKaWRpb3Rfc2VudGltZW50W2lkaW90X3NlbnRpbWVudCRwYXJ0ID09ICJQQVJUIEkiLCAicGFydF9saW5lbnVtYmVyIl0gPSBzZXFfYWxvbmcoMToocGFydF8yX3N0YXJ0IC0gMSkpCmlkaW90X3NlbnRpbWVudFtpZGlvdF9zZW50aW1lbnQkcGFydCA9PSAiUEFSVCBJSSIsICJwYXJ0X2xpbmVudW1iZXIiXSA9IHNlcV9hbG9uZyhwYXJ0XzJfc3RhcnQ6KHBhcnRfM19zdGFydC0xKSkKaWRpb3Rfc2VudGltZW50W2lkaW90X3NlbnRpbWVudCRwYXJ0ID09ICJQQVJUIElJSSIsICJwYXJ0X2xpbmVudW1iZXIiXSA9IHNlcV9hbG9uZyhwYXJ0XzNfc3RhcnQ6KHBhcnRfNF9zdGFydC0xKSkKaWRpb3Rfc2VudGltZW50W2lkaW90X3NlbnRpbWVudCRwYXJ0ID09ICJQQVJUIElWIiwgInBhcnRfbGluZW51bWJlciJdID0gc2VxX2Fsb25nKHBhcnRfNF9zdGFydDpkaW0oaWRpb3Rfc2VudGltZW50KVsxXSkKI2hlYWQoaWRpb3Rfc2VudGltZW50JHBhcnQpCiN0YWlsKGlkaW90X3NlbnRpbWVudCRwYXJ0KQpgYGAKCgpgYGB7cn0KdGhlbWVfc3l1emhldCA8LSAjdGhlbWVfdHVmdGUoKSArCiAgdGhlbWUoYXhpcy50aWNrcyA9ZWxlbWVudF9saW5lKCkpICsKICB0aGVtZShheGlzLnRleHQgPWVsZW1lbnRfdGV4dChzaXplPTYpKSArCiAgdGhlbWUocGFuZWwuYm9yZGVyPWVsZW1lbnRfYmxhbmsoKSkgKwogIHRoZW1lKGxlZ2VuZC50aXRsZT1lbGVtZW50X3RleHQoc2l6ZT02KSkgKwogIHRoZW1lKGxlZ2VuZC50aXRsZS5hbGlnbj0xKSArCiAgdGhlbWUobGVnZW5kLnRleHQ9ZWxlbWVudF90ZXh0KHNpemU9NikpICsKICB0aGVtZShsZWdlbmQucG9zaXRpb249ImJvdHRvbSIpICsKICB0aGVtZShsZWdlbmQua2V5LnNpemU9dW5pdCgwLjIsICJjbSIpKSArCiAgdGhlbWUobGVnZW5kLmtleS53aWR0aD11bml0KDEsICJjbSIpKSAKCnRoZW1lX3N5dXpoZXRfbm9feF9heGlzIDwtIHRoZW1lX3N5dXpoZXQgKwogIHRoZW1lKGF4aXMudGlja3M9ZWxlbWVudF9ibGFuaygpLCBheGlzLnRleHQueD1lbGVtZW50X2JsYW5rKCkpIAogIApgYGAKRmluYWxseSB3ZSBjYW4gcGxvdCBleHRyYWN0ZWQgc2VudGltZW50LiBXZSB1c2UgZGlmZmVyZW50IGNvbG91cnMgZm9yIGRpZmZlcmVudCBzZW50aW1lbnQgZXh0cmFjdGlvbiBtZXRob2QuCgpgYGB7cn0KaWRpb3Rfc2VudGltZW50X2J5X21ldGhvZCA8LSBpZGlvdF9zZW50aW1lbnQgJT4lCiAgICAgICAgICAgIHNlbGVjdChsaW5lbnVtYmVyLCBwYXJ0X2xpbmVudW1iZXIsIHBhcnQsCiAgICAgICAgICAgICAgICAgIHN5dXpoZXRfZW1vdGlvbmFsX3ZhbGVuY2UsCiAgICAgICAgICAgICAgICAgIGJpbmdfZW1vdGlvbmFsX3ZhbGVuY2UsCiAgICAgICAgICAgICAgICAgIGFmaW5uX2Vtb3Rpb25hbF92YWxlbmNlLAogICAgICAgICAgICAgICAgICBucmNfZW1vdGlvbmFsX3ZhbGVuY2UpICU+JQogICAgICAgIGdhdGhlcihtZXRob2QsIGVtb3Rpb25hbF92YWxlbmNlLCBzeXV6aGV0X2Vtb3Rpb25hbF92YWxlbmNlIDogbnJjX2Vtb3Rpb25hbF92YWxlbmNlKQpnZ3Bsb3QoaWRpb3Rfc2VudGltZW50X2J5X21ldGhvZCwgYWVzKHggPSBwYXJ0X2xpbmVudW1iZXIsIHkgPSBlbW90aW9uYWxfdmFsZW5jZSwgY29sb3IgPSBtZXRob2QpKSArCiAgZ2VvbV9wb2ludChhbHBoYSA9IDAuNCwgc2l6ZSA9IDAuNSkgKwogIGZhY2V0X3dyYXAofnBhcnQsIG5yb3cgPSA0KSArCiAgdGhlbWVfc3l1emhldCArCiAgbGFicyh5PSJTZW50aW1lbnQgU2NvcmUiLCB4PSJOYXJyYXRpdmUgTGVuZ2h0IiwgdGl0bGUgPSBleHByZXNzaW9uKHBhc3RlKCJFbW90aW9uYWwgVmFsZW5jZSBpbiAiLCBpdGFsaWMoIlRoZSBJZGlvdCIpKSkpIApgYGAKVGhlc2UgcGxvdHMgbmVlZCB6b29taW5nIHRvIGJlIHJlYWJhYmxlLCBidXQgd2UgY2FuIHNlZSB0aGF0IHNjYWxlcyB1c2VkIGJ5IGRpZmZlcmVudCBtZXRob2RzIGFyZSBzbGlnaHRseSBkaWZmZXJlbnQgYW5kIHNvbWUgb2YgdGhlbSBnaXZlIG9ubHkgZGlzY3JldGUgdmFsdWVzLiBEZWZpbmF0ZWx5IHBsb3R0aW5nIHRoZXNlIGFzIHBvaW50IHBsb3RzIG1pZ2h0IG5vdCB0aGUgYmVzdCBpZGVhLCBsZXQncyB0cnkgbGluZSBwbG90IGluc3RlYWQuCgpgYGB7cn0KZ2dwbG90KGlkaW90X3NlbnRpbWVudF9ieV9tZXRob2QsIGFlcyh4ID0gcGFydF9saW5lbnVtYmVyLCB5ID0gZW1vdGlvbmFsX3ZhbGVuY2UsIGNvbG9yID0gbWV0aG9kKSkgKwogIGdlb21fbGluZShhbHBoYSA9IDAuNSkgKwogIGZhY2V0X3dyYXAofnBhcnQsICBucm93ID0gNCkgKwogIHRoZW1lX3N5dXpoZXQgKwogIGxhYnMoeT0iU2VudGltZW50IFNjb3JlIiwgeD0iTmFycmF0aXZlIExlbmdodCIsIHRpdGxlID0gZXhwcmVzc2lvbihwYXN0ZSgiRW1vdGlvbmFsIFZhbGVuY2UgaW4gIiwgaXRhbGljKCJUaGUgSWRpb3QiKSkpKSAKYGBgCldpdGggbGluZXBsb3RzIHdlIHN0YXJ0IHR3byBub3RpY2UgYmV0dGVyIGdlbmVyYWwgdmFyaWFiaWxpdHkgb2YgZW1vdGlvbmFsIHZhbGFuY2UsIGFuZCBzb21lIGV4dHJlbWUgcG9pbnRzLiBXZSB3aWxsIGV4YW1pbmUgdGhlc2UgZXh0cmVtZSBwb2ludHMgbm93IHRvIGdldCBiZXR0ZXIgaW50dXRpb25zIGFib3V0IG51bWJlcnMgd2UgYXJlIG9idGFpbmluZy4gV2Ugem9vbSBpbiBhIGJpdCBhdCBwb2ludHMgd2l0aCBzdHJvbmdlc3QgbmVnYXRpdmUgZW1vdGlvbnMuCmBgYHtyfQppZGlvdF9zZW50aW1lbnRfYnlfbWV0aG9kICU+JSBmaWx0ZXIobGluZW51bWJlciA+IDMwMCwgbGluZW51bWJlciA8IDUwMCkgJT4lCmdncGxvdCggYWVzKHggPSBsaW5lbnVtYmVyLCB5ID0gZW1vdGlvbmFsX3ZhbGVuY2UsIGNvbG9yID0gbWV0aG9kKSkgKwogIGdlb21fbGluZShhbHBoYSA9IDAuNSkgKwogIHRoZW1lX3N5dXpoZXQgKwogIGxhYnMoeT0iU2VudGltZW50IFNjb3JlIiwgeD0iTmFycmF0aXZlIExlbmdodCIsIHRpdGxlID0gZXhwcmVzc2lvbihwYXN0ZSgiRW1vdGlvbmFsIFZhbGVuY2UgaW4gIiwgaXRhbGljKCJUaGUgSWRpb3QiKSwiIC0gbGluZXMgMzAwIC0gNTAwIikpKSAKYGBgCmBgYHtyfQppZGlvdF9zZW50aW1lbnQgJT4lIGZpbHRlcihsaW5lbnVtYmVyID49IDQwNSwgbGluZW51bWJlciA8IDQxNSkKYGBgClNlZW1zIGxpa2UgbGluZSA0MDYgaXMgdGhlIG1vc3QgbmVnYXRpdmUgb25lLgpgYGB7cn0KaWRpb3Rfc2VudGltZW50ICU+JSBmaWx0ZXIobGluZW51bWJlciA9PSA0MDYpICU+JSBzZWxlY3QodGV4dCkKYGBgClRoaXMgc3VyZWx5IHNvdW5kcyBuZWdhdGl2ZSAtIGxldHMgc2VlIHdoYXQgb3RoZXIgZW1vdGlvbnMgaXQgY29udmV5cy4KYGBge3J9CmVtb3Rpb25zIDwtIGMoImFuZ2VyIiwgImFudGljaXBhdGlvbiIsICJkaXNndXN0IiwgImZlYXIiLCAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAiam95IiwgInNhZG5lc3MiLCAic3VycHJpc2UiLCAidHJ1c3QiKQppZGlvdF9zZW50aW1lbnQgJT4lIGZpbHRlcihsaW5lbnVtYmVyID09IDQwNikgJT4lIHNlbGVjdChvbmVfb2YoZW1vdGlvbnMpKQpgYGAKRW1vdGlvbnMgY2FwdHVyZWQgaW4gdGhlIHNlbnRlbmNlIG9idmlvdXNseSBkZXBlbmQgb24gbGFyZ2VyIGNvbnRleHQsIGJ1dCBqdWRnaW5nIGJ5IHNlbnRlbmNlIGl0c2VsZiwgYXV0aG9tYXRpY2FsbHkgcmVjb2duaXplZCBlbW90aW9ucyBhcmUgcXVpdGUgYWNjdXJhdGUuIApMZXQncyBsb29rIGF0IGFub3RoZXIgbG93IHBvaW50IC0gYXJvdW5kIGxpbmUgbnVtYmVyIDEwMDAwLgpgYGB7cn0KaWRpb3Rfc2VudGltZW50X2J5X21ldGhvZCAlPiUgZmlsdGVyKGxpbmVudW1iZXIgPiAxMDAwMCwgbGluZW51bWJlciA8IDEwMTAwKSAlPiUKZ2dwbG90KCBhZXMoeCA9IGxpbmVudW1iZXIsIHkgPSBlbW90aW9uYWxfdmFsZW5jZSwgY29sb3IgPSBtZXRob2QpKSArCiAgZ2VvbV9saW5lKGFscGhhID0gMC41KSArCiAgdGhlbWVfc3l1emhldCArCiAgbGFicyh5PSJTZW50aW1lbnQgU2NvcmUiLCB4PSJOYXJyYXRpdmUgTGVuZ2h0IiwgdGl0bGUgPSBleHByZXNzaW9uKHBhc3RlKCJFbW90aW9uYWwgVmFsZW5jZSBpbiAiLCBpdGFsaWMoIlRoZSBJZGlvdCIpLCIgLSBsaW5lcyAxMDAwMCAtIDEwMTAwIikpKSAKYGBgCmBgYHtyfQppZGlvdF9zZW50aW1lbnQgJT4lIGZpbHRlcihsaW5lbnVtYmVyID49IDEwMDI1LCBsaW5lbnVtYmVyIDwgMTAwMzUpCmBgYApUaGlzIHRpbWUgbGluZSAxMDAzMCBpcyB0aGUgbW9zdCBuZWdhdGl2ZS4KYGBge3J9CmlkaW90X3NlbnRpbWVudCAlPiUgZmlsdGVyKGxpbmVudW1iZXIgPT0gMTAwMzApICU+JSBzZWxlY3QodGV4dCkKYGBgCmBgYHtyfQppZGlvdF9zZW50aW1lbnQgJT4lIGZpbHRlcihsaW5lbnVtYmVyID09IDEwMDMwKSAlPiUgc2VsZWN0KG9uZV9vZihlbW90aW9ucykpCmBgYApBZ2FpbiAtIGl0IHNlZW1zIHRoYXQgb3VyIG1ldGhvZCBtaWdodCBiZSBvZmYsIGJ1dCBhZ2FpbiByZWFzb25hYmx5IHNvLgoKSGF2aW5nIGJldHRlciB1bmRlcnN0YW5kaW5nIGFuZCBzb21lIHByb29mIG9mIGFjY3VyYWN5IG9mIG9idGFpbmVkIHNjb3JlcyBsZXQncyBjb21lIGJhY2sgdG8gb3VyIGNvbXBhcmlzb24uIExldCdzIHRyeSBwbG90dGluZyBzbW9vdGhlZCB2YWx1ZXMgZm9yIGRpZmZlcmVudCBzY29yaW5nIG1ldGhvZHMuIApgYGB7cn0KZ2dwbG90KGlkaW90X3NlbnRpbWVudF9ieV9tZXRob2QsIGFlcyh4ID0gcGFydF9saW5lbnVtYmVyLCB5ID0gZW1vdGlvbmFsX3ZhbGVuY2UsIGNvbG9yID0gbWV0aG9kKSkgKwogIGdlb21fc21vb3RoKGFscGhhID0gMC41LCBzZT0gRkFMU0UpICsKICBmYWNldF93cmFwKH5wYXJ0LCBucm93ID0gNCkgKwogIHRoZW1lX3N5dXpoZXQgKwogIGxhYnMoeT0iU2VudGltZW50IFNjb3JlIiwgeD0iTmFycmF0aXZlIExlbmdodCIsIHRpdGxlID0gZXhwcmVzc2lvbihwYXN0ZSgiRW1vdGlvbmFsIFZhbGVuY2UgaW4gIiwgaXRhbGljKCJUaGUgSWRpb3QiKSwiIC0gc21vb3RoZWQiKSkpIAoKYGBgClBsb3QgcHJlc2VudHMgc21vb3RoZWQgc2VudGltZW50cyBjb211dGVkIHdpdGggZGlmZmVyZW50IG1ldGhvZHMuIFNtb290aGluZyBpcyBkb25lIGJ5IGZpdHRpbmcgR0FNKEdlbmVyYWxpemVkIEFkZGl0aXZlIE1vZGVsKSB0byB0aGUgZGF0YSwgY3VydmUgaXMgYXBwcm94aW1hdGVkIGJ5IHNwbGluZS4gV2Ugc2VlIHRoYXQgYWxsIGN1cnZlcyBzaGFyZSB0aGUgc2FtZSBiYXNpYyBzaGFwZS4gRm9yIHRoZSBmdXJ0aGVyIGFuYWx5c2lzIHdlIHdpbGwgdXNlIFN5dXpoZXQgZGVmYXVsdCBzZW50aW1lbnQgdmFsZW5jZSBlc3RpbWF0aW9uIG1ldGhvZC4gUmVzdCBvZiB0aGUgc2VudGltZW50cyB3aWxsIGJlIG1lYXN1cmVkIHdpdGggTlJDIG1ldGhvZC4KCkZpcnN0IGxldCdzIGFnYWluIGxvb2sgYXQgdGhlIHBsb3QuIFRoaXMgdGltZSBpbnN0ZWFkIG9mIGdncGxvdCB3ZSB1c2UgcGxvdHRpbmcgY2FwYWJpbGl0aWVzIG9mIFN5dXpoZXQuIFNoYXBlIGlzIGRpZmZlcmVudCBoZXJlLCBhcyB3ZSB1c2Ugc2luZ2xlIGN1cnZlIGZvciB0aGUgd2hvbGUgbm92ZWwsIGFuZCB3ZSB1c2UgZGlmZmVyZW50IHNtb3RoaW5nIG1ldGhvZC4gR2VuZXJhbCBzaGFwZSBvZiB0aGUgY3VydmUgc2VlbXMgdG8gYmUgYWN1cnJhdGVseSByZXByZXNlbnRpbmcgdGhlIG5vdmVsLiBBdCB0aGUgYmVnaW5uaW5nIG9mIHRoZSBub3ZlbCB0aGVyZSBhcmUgbWFueSBwb3N0aXZlIGVtb3Rpb25zIHdoaWNoIGdvIHN0ZWFkaWx5IG1vcmUgbmVnYXRpdmUgdW50aWwgdGhlIG1pZGRsZSBvZiBmaXJzdCBwYXJ0LiBGcm9tIHRoaXMgcG9pbnQgc2VudGltbnQgaXMgb3NjaWxhdGluZyBidXQgc3RheXMgb24gdGhlIG5lZ2F0aXZlIHNpZGUuIEZpbmFsbHkgd2UgcmVhY2ggdGhlIGxvd2VzdCBwb2ludCBhcm91bmQgbGluZSAxMDAwMCAtIDExMDAwLiBUaGlzIGlzIHRoZSBwb2ludCByb3VuZCB0aGUgZW5kIG9mIHBhcnQgMyBhbmQgYmVnZ2luaW5nIG9mIHBhcnQgNC4gRnJvbSB0aGlzIHBvaW50IGVtb3Rpb24gc3RlYWRpbHkgcmlzZSB1dGlsIHRoZSBlbmRpbmcgd2hpY2ggaXMgYWdhaW4gb24gdGhlIHNhZCBub3RlLiBUaGlzIHJlZmxlY3RzIGV2ZW50IGluIHRoZSBub3ZlbCB3ZWxsLCBhbHRob3VnaHQgc29tZSBvZiB0aGUgcGxvdHMgLSBlLmcuIHNpbXBsaWZpZWQgbWFjcm8gc2hhcGUgZG9uJ3QgY2FwdHVyZSBkaXAgYXQgdGhlIGVuZCBvZiB0aGUgbm92ZWwuCgpgYGB7cn0Kc2ltcGxlX3Bsb3QoaWRpb3Rfc2VudGltZW50JHN5dXpoZXRfZW1vdGlvbmFsX3ZhbGVuY2UpCmBgYApOb3cgbGV0J3MgaW5zcGVjdCBob3cgZGlmZmVyZW50IGVtb3Rpb25zIGFwcGVhciBpbiB0aGUgbm92ZWwuCgpgYGB7cn0KZW1vdGlvbnMgPC0gaWRpb3Rfc2VudGltZW50ICU+JSBzZWxlY3QobGluZW51bWJlciwgcGFydCwgcGFydF9saW5lbnVtYmVyLCBhbmdlciwgYW50aWNpcGF0aW9uLCAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBkaXNndXN0LCBmZWFyLCBqb3ksIHNhZG5lc3MsIHN1cnByaXNlLCAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICB0cnVzdCkgJT4lIAogICAgICAgIGdhdGhlcihzZW50aW1lbnQsIHZhbHVlLCBhbmdlcjp0cnVzdCkKZW1vdGlvbnMkc2VudGltZW50IDwtIGFzX2ZhY3RvcihlbW90aW9ucyRzZW50aW1lbnQpCmVtb3Rpb25zJHNlbnRpbWVudCA8LSBmY3RfcmVsZXZlbChlbW90aW9ucyRzZW50aW1lbnQsIGMoImpveSIsInRydXN0IiwiYW50aWNpcGF0aW9uIiwic3VycHJpc2UiLCJzYWRuZXNzIiwiZGlzZ3VzdCIsImZlYXIiLCJhbmdlciIpKQpoZWFkKGVtb3Rpb25zKQpgYGAKCmBgYHtyfQplbW90aW9ucyAlPiUKICBnZ3Bsb3QoYWVzKHggPSBwYXJ0X2xpbmVudW1iZXIsIHkgPSBzZW50aW1lbnQsIGZpbGwgPSB2YWx1ZSkpICsKICBnZW9tX3RpbGUod2lkdGggPSAzKSArCiAgZmFjZXRfd3JhcCh+cGFydCwgbnJvdyA9IDQpICsKICBzY2FsZV9maWxsX3ZpcmlkaXMobmFtZT0iU2VudGltZW50XG5TY29yZSIpICsKICBsYWJzKHg9TlVMTCwgeT1OVUxMLCB0aXRsZT1leHByZXNzaW9uKHBhc3RlKCJTZW50aW1lbnQgaW4gIiwgaXRhbGljKCJUaGUgSWRpb3QiKSkpKSArCiAgdGhlbWVfdHVmdGUoKSArCiAgdGhlbWVfc3l1emhldCArCiAgc2NhbGVfeF9kaXNjcmV0ZShleHBhbmQ9YygwLDApKQoKYGBgCk9uIHRoZSBwbG90IHdlIG5lZ2F0aXZlIGVtb3Rpb24gaW4gdGhlIGhpZ2hlciBwYXJ0cyBvZiB0aGUgc3RyaXBlIGFuZCBwb3NpdGl2ZSBvbmVzIGluIHRoZSBsb3dlciBwYXJ0LiBJbiBnZW5lcmFsIHdlIHNlZSB0aGF0IHNlbnRpbWVudCBzY29yZSBzdGF5cyBsb3cgbW9zdCBvZiB0aGUgdGltZSwgYnV0IHRoZXJlIGFyZSBwYXJ0aWN1bGFyIGVwaXNvZGVzKGluIHBhcnRpY3VsYXIgaW4gZmlzdCBwYXJ0KSB3aXRoIHN0cm9uZ2VyIG5lZ2F0aXZlIGFuZCBwb3NpdGl2ZSBlbW90aW9ucy4gCk5vdyBsZXQncyB0cnkgbWFraW5nIHVzZSBvZiBtb3JlIGNvbXBsZXggZnVuY3Rpb25hbGl0aWVzIG9mIFN5dXpoZXQuCgoKYGBge3J9Cmd1dGVuYmVyZ19zZW50aW1lbnRzIDwtIGZ1bmN0aW9uKHdvcmspIHsKICBzZW50ZW5jZV92IDwtIGdldF9zZW50ZW5jZXMod29yayR0ZXh0KQogIGxpbmVudW1iZXIgPC0gc2VxX2Fsb25nKHNlbnRlbmNlX3YpCiAgZW1vdGlvbmFsX3ZhbGVuY2UgPC0gZ2V0X3NlbnRpbWVudChzZW50ZW5jZV92LCBtZXRob2Q9InN5dXpoZXQiKQogIG5yY19zZW50aW1lbnQgPC0gZ2V0X25yY19zZW50aW1lbnQoc2VudGVuY2VfdikKICBjYmluZCgKICAgIHRpYmJsZShsaW5lbnVtYmVyID0gbGluZW51bWJlciwKICAgICAgICAgIHRleHQgPSBzZW50ZW5jZV92LAogICAgICAgICAgZW1vdGlvbmFsX3ZhbGVuY2UgPSBlbW90aW9uYWxfdmFsZW5jZSksCiAgICBucmNfc2VudGltZW50KQp9CgpzZW50aW1lbnRfdHJhbmZvcm1lZCA8LSBmdW5jdGlvbihzZW50aW1lbnQsIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBjb2x1bW5zLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBmdW5jID0gZ2V0X2RjdF90cmFuc2Zvcm0pIHsKICB0cmFuc2Zvcm1lZF9saXN0IDwtIGNvbHVtbnMgJT4lIG1hcCh+IGZ1bmMoc2VudGltZW50WywueF0pKQogIG5hbWVzKHRyYW5zZm9ybWVkX2xpc3QpIDwtIGNvbHVtbnMKICB0cmFuc2Zvcm1lZF9saXN0W1siaW5kZXgiXV0gPC0gc2VxX2Fsb25nKHRyYW5zZm9ybWVkX2xpc3RbWzFdXSkKICBhcy50aWJibGUodHJhbnNmb3JtZWRfbGlzdCkKfQoKZW1vdGlvbl9jb2x1bW5zID0gYygiam95IiwidHJ1c3QiLCJhbnRpY2lwYXRpb24iLCJzdXJwcmlzZSIsInNhZG5lc3MiLCJkaXNndXN0IiwiZmVhciIsImFuZ2VyIikKdmFsZW5jZV9hbmRfZW1vdGlvbnMgPSBjKCJlbW90aW9uYWxfdmFsZW5jZSIsIGVtb3Rpb25fY29sdW1ucykKCmVtb3Rpb25hbF9zdW1tYXJ5IDwtIGZ1bmN0aW9uKHNlbnRpbWVudCkgewogIGNvbFN1bXMocHJvcC50YWJsZShzZW50aW1lbnRbLGVtb3Rpb25fY29sdW1uc10pKQp9CmBgYAoKYGBge3J9CmlkaW90X3NlbnRpbWVudFsiZW1vdGlvbmFsX3ZhbGVuY2UiXSA8LSBpZGlvdF9zZW50aW1lbnRbInN5dXpoZXRfZW1vdGlvbmFsX3ZhbGVuY2UiXQppZGlvdF9kY3RfdHJhbmZvcm1lZCA8LSBzZW50aW1lbnRfdHJhbmZvcm1lZChpZGlvdF9zZW50aW1lbnQsIHZhbGVuY2VfYW5kX2Vtb3Rpb25zKQppZGlvdF9mb3VyaWVyX3RyYW5zZm9ybWVkIDwtIHNlbnRpbWVudF90cmFuZm9ybWVkKGlkaW90X3NlbnRpbWVudCwgdmFsZW5jZV9hbmRfZW1vdGlvbnMsIGdldF90cmFuc2Zvcm1lZF92YWx1ZXMpCmBgYAoKU3l1emhldCBoYXZlIHR3byBtZXRob2RzIG9mIGNyZWF0aW5nIGN1cnZlcyBhcHJveGltYXRpbmcgImVtb3Rpb25hbCBzaGFwZSIgb2YgdGhlIG5vdmVsIC0gYnkgRm91cmllciB0cmFuc2Zvcm0gd2l0aCBsb3cgcGFzcyBmaWx0ZXIgYW5kIGJ5IERpc2NyZXRlIENvc2luZSBUcmFuc3BvcnQoZGN0KS4gV2UgaW5zcGVjdCBib3RoIG1ldGhvZHMuCmBgYHtyfQppZGlvdF9kY3RfdHJhbmZvcm1lZFsibWV0aG9kIl0gPC0gImRjdCIKaWRpb3RfZm91cmllcl90cmFuc2Zvcm1lZFsibWV0aG9kIl0gPC0gImZvdXJpZXIiCmlkaW90X2ZvdXJpZXJfdHJhbnNmb3JtZWQgJT4lIGdhdGhlcihzZW50aW1lbnQsIHZhbHVlLCBqb3k6YW5nZXIpICU+JQpnZ3Bsb3QoYWVzKHggPSBpbmRleCwgeSA9IHZhbHVlLCBjb2xvciA9IHNlbnRpbWVudCkpICsKICBsYWJzKHk9IlNlbnRpbWVudCBTY29yZSIsIHg9Ik5vcm1hbGl6ZWQgTmFycmF0aXZlIExlbmd0aCIpICsKICBnZW9tX2xpbmUoKSArCiAgdGhlbWVfc3l1emhldApgYGAKCkZpcnN0IGxldCdzIHNlZSBlZmZlY3Qgb2YgdXNpbmcgRm91cmllciB0cmFuc2Zvcm0gdG8gZ2V0IHNtb290aGVyIHZlcnNpb24gb2Ygc2VudGltZW50IGN1cnZlcyBmb3IgVGhlIElkaW90LiBXZSBzZWUgYXJ0aWZhY3RzIGF0IHRoZSBiZWdpbm5pbmcgYW5kIGF0IHRoZSBlbmQgb2YgdGhlIG5vdmVsLiBUaGV5IGFyZSBkdWUgdG8gcGVyaW9kaWNpdHkgb2YgZm91cmllciBmdW5jdGlvbnMuIFRoaXMgcHJvYmxlbSB3YXMgbm90aWNlZCBieSBhdXRob3JzIGFuZCBvdGhlcnMgaHR0cHM6Ly9hbm5pZXN3YWZmb3JkLndvcmRwcmVzcy5jb20vMjAxNS8wMy8zMC93aHktc3l1emhldC1kb2VzbnQtd29yay1hbmQtaG93LXdlLWtub3cvIG5kIG90aGVyIGh0dHA6Ly93d3cubWF0dGhld2pvY2tlcnMubmV0LyAuIFRoaXMgaXMgd2h5IGN1cnJlbnRseSBhdXRob3IgcmVjb21tZW5kcyB1c2luZyBvdGhlciBtZXRob2QuIFN0aWxsIHBsb3QgZ2l2ZXMgdXMgaWRlYSB3aGljaCBlbW90aW9uYSBhcmUgbW9zdCBzdHJvbmdseSBleHByZXNzZWQgdGhyb3VnaCB0aGUgbmFycmF0dmUuIFdlIHNlZSB0aGF0IGFsbCBlbW90aW9ucyBoYXZlIHNpbWlsYXIgYmFzZSBzaGFwZSwgYnV0IHNsaWdodGx5IGRpZmZlcmVudCBsZXZlbHMuCgoKYGBge3J9CmlkaW90X2RjdF90cmFuZm9ybWVkICU+JSBnYXRoZXIoc2VudGltZW50LCB2YWx1ZSwgam95OmFuZ2VyKSAlPiUKZ2dwbG90KGFlcyh4ID0gaW5kZXgsIHkgPSB2YWx1ZSwgY29sb3IgPSBzZW50aW1lbnQpKSArIGdlb21fbGluZSgpICsgdGhlbWVfc3l1emhldApgYGAKCkRDVCB0cmFuZnJvbSBnaXZlcyBzbGlnaHRseSBkaWZmZXJlbnQgcGljdHVyZS4gQXJ0aWZpY2FsIGRpcHMgYXQgdGhlIGJlZ2dpbmluZyBhbmQgYXQgdGhlIGVuZCBvZiB0aGUgbm92ZWwgYW5kIG5vdCBwcmVzZW50IGFueW1vcmUuIFdlIHNlZSB0aGF0IHRydXN0LCBhbnRpY2lwYXRpb24gYW5kIGpveSBhbmQgc3VycHJpc2Ugb3NjaWxhdGluZyB0aHJvdWdoIHRoZSBuYXJyYXRpdmUgdGltZSwgc3RhcnRpbmcgaGlnaCwgYW5kIGhhdmluZyB0d28gbG93IHBvaW50cyBhcm91bmQgMS80LXRoIGFuZCAzLzR0aCBvZiB0aGUgbmFycml2ZSB0aW1lLCB3aGlsZSBuZWdhdGl2ZSBlbW90aW9ucyBsaWtlIGFuZ2VyLCBzYWRuZXNzIGFuZCBkaXNndXN0IHN0YXJ0IG9uIHRoZSBsb3dlciBwb2ludCBhbmQgc2xvd2x5IHJhaXNlLCB1bnRpbCB0aGUgaGlnaGVzdCBwb2ludCB3aGljaCBoYXBwZW5zIGFmdGVyIHRoZSBoYWxmIG9mIHRoZSBub3ZlbChsYXRlciBmb3IgZGlzZ3VzdCkuIEZyb20gdGhpcyBwb2ludCB0aGV5IGxvd2VyIHNsaWdobHkgdW50aWwgdGhlIGVuZCBvZiB0aGUgbm92ZWwuCkhhdmluZyB3ZWxsIGFubm90YXRlZCBub3ZlbCBjb3VsZCBhbGxvdyB1cyB0byBjb25uZWN0IGNlcnRhaW4gc2VudGltZW50cyB0byBzcGVjaWZpYyBtb21lbnQgaW4gdGhlIG5hcnJhdGl2ZS4gQXQgdGhlIGN1cnJlbnQgbW9tZW50IGNvbmR1Y3Rpbmcgc3VjaCBhbmFseXNpcyBpcyByYXRoZXIgaGFyZCwgbm9yIGxvbmcgYW5kIGNvbXBsZXggbm92ZWwgbGlrZSBUaGUgSWRpb3QgYW5kIHJlcXVpcmVzIHZlcnkgZ29vZCBrbm93bGVnZGUgb2YgdGhlIHRleHQuCgpBbHRob3VnaCB0cmFzbmZvcm1hdGlvbnMgYXJlIHVzZWZ1bGwgaW4gY29uZHVjdGluZyBhbmFseXNpcyBvZiBnZW5lcmFsIHRoZW1lIG9mIHRoZSB0ZXh0LCBpIGJlbGlldmUgb25lIG9mIGl0J3MgbWFpbiBhZHZhbnRlZGVnIGlzIGl0J3Mgbm9ybWFsaXppbmcgZWZmZXQgd2hpY2ggYWxsb3dzIHVzdCB0byBjb21wYXJlIGRpZmZlcmVudCB0ZXh0cy4gVG8gZXhwbG9yZSB0aGlzIHBvc3NpYmlsaXR5IEkgY29uZHVjdCBzaW1wbGUgYW5hbHlzaXMgb2YgZW1vdGlvbmFsIHZhbGVuY2UgYW5kIGV4cHJlc3NlZCBzZW50aW1lbnQgaW4gdGhlIG1vc3QgZmFtb3VzIHdvcmtzIG9mIEZ5b2RvciBEb3N0b3lldnNreSBhbmQgTGVvIFRvbHN0b3kuCgpgYGB7cn0KZ3V0ZW5iZXJnX3dvcmtzKGF1dGhvciA9PSAiRG9zdG95ZXZza3ksIEZ5b2RvciIsIGxhbmd1YWdlID09ICJlbiIpIApgYGAKYGBge3J9Cm5vdGVzX2Zyb21fdW5kZXJncm91bmQgPC0gZ3V0ZW5iZXJnX2Rvd25sb2FkKDYwMCkKZ2FtYmxlciA8LWd1dGVuYmVyZ19kb3dubG9hZCgyMTk3KQpjcmltZV9hbmRfcHVuaXNobWVudCA8LSBndXRlbmJlcmdfZG93bmxvYWQoMjU1NCkKYnJvdGhlcnNfa2FyYW1hem92IDwtIGd1dGVuYmVyZ19kb3dubG9hZCgyODA1NCkKd2hpdGVfbmlnaHRzIDwtIGd1dGVuYmVyZ19kb3dubG9hZCgzNjAzNCkKYGBgCmBgYHtyfQpndXRlbmJlcmdfd29ya3MoYXV0aG9yID09ICJUb2xzdG95LCBMZW8sIGdyYWYiLCBsYW5ndWFnZSA9PSAiZW4iKSAKYGBgCmBgYHtyfQojZmF0aGVyX3NlcmdpdXMgPC0gZ3V0ZW5iZXJnX2Rvd25sb2FkKDk4NSkKd2FyX2FuZF9wZWFjZSA8LSBndXRlbmJlcmdfZG93bmxvYWQoMjYwMCkKbWFzdGVyX2FuZF9tYW4gPC0gZ3V0ZW5iZXJnX2Rvd25sb2FkKDk4NikKYW5uYV9rYXJlbmluYSA8LSBndXRlbmJlcmdfZG93bmxvYWQoMTM5OSkKcmVzdXJyZWN0aW9uIDwtIGd1dGVuYmVyZ19kb3dubG9hZCgxOTM4KQpgYGAKSSB1c2UgUHJvamVjdCBHdXRlYmVyZyBhZ2FpbiBmb3IgdGhpcyBhaW0uIEkgdGFrZSA2IHdvcmtzIGZyb20gRnlvZG9yIERvc3RveWV2c2t5IC0gTm90ZXMgZnJvbSB0aGUgVW5kZXJncm91bmQsIEdhbWJsZXIsIFdoaXRlIE5pZ2h0cywgQ3JpbWUgYW5kIFB1bmlzaG1lbnQsIElkaW90IGFuZCBCcm90aGVycyBLYXJhbWF6b3YuIEkgd2FudGVkIHRvIGluY3VkZSBib3RoIDMgJ2dyZWF0ZXN0JyB3b3JrcyBvZiBEb3N0b3lldnNreSBhcyB3ZWxsIGFzIHNvbWUgYWNjbGFpbWVkIHNob3J0ZXIgd29ya3MuIFNpbWlsYXJseSBmb3IgTGVvIFRveWxzdG8gSSBhbmFseXplIGhpcyAyIG1vc3QgZmFtb3VzdCB3b3JrcyBBbm5hIEthcmVuaW5hIGFuZCBXYXIgYW5kIFBlYWNlLCBhbmQgdHdvIG9mIHRoZSBsYXRlciB3b3JrIC0gTWFzdGVyIGFuZCBNYW4gYW5kIFJlc3VycmVjdGlvbi4gCgpgYGB7cn0KYXV0aG9yX3NlbnRpbWVudHMgPC0gZnVuY3Rpb24od29ya3MpIHsKICAgd29ya3MgJT4lCiAgICBtYXAoZ3V0ZW5iZXJnX3NlbnRpbWVudHMpCn0KCmF1dGhvcl9lbW90aW9uYWxfc3VtbWFyeSA8LSBmdW5jdGlvbih3b3JrcykgewogIHdvcmtzICU+JQogICAgbWFwKH5lbW90aW9uYWxfc3VtbWFyeShndXRlbmJlcmdfc2VudGltZW50cygueCkpKSAlPiUKICAgIG1hcDIobmFtZXMod29ya3MpLCB+IGMoLngsIHRpdGxlID0gLnkpKSAlPiUKICAgIHJlZHVjZShyYmluZCkKfQoKYXV0aG9yX3ZhbGVuY2UgPC0gZnVuY3Rpb24od29ya3MpIHsKICB3b3JrcyAlPiUKICAgIG1hcCh+IHNlbnRpbWVudF90cmFuZm9ybWVkKGd1dGVuYmVyZ19zZW50aW1lbnRzKC54KSwgYygiZW1vdGlvbmFsX3ZhbGVuY2UiKSkpICU+JQogICAgbWFwMl9kZihuYW1lcyh3b3JrcyksIH4gbXV0YXRlKC54LCB0aXRsZSA9IC55KSkKfQoKYGBgCgpgYGB7cn0KCnRvbHN0b3lfd29ya3MgPC0gbGlzdCh3YXJfYW5kX3BlYWNlLCBhbm5hX2thcmVuaW5hLCBtYXN0ZXJfYW5kX21hbiwgcmVzdXJyZWN0aW9uKQpuYW1lcyh0b2xzdG95X3dvcmtzKSA8LSBjKCJXYXIgYW5kIFBlYWNlIiwgIkFubmEgS2FyZW5pbmEiLCJNYXN0ZXIgYW5kIE1hbiIsICJSZXN1cnJlY3Rpb24iKQp0b2xzdG95X2Vtb3Rpb25hbF92YWxlbmNlIDwtIGF1dGhvcl92YWxlbmNlKHRvbHN0b3lfd29ya3MpCnRvbHN0b3lfZW1vdGlvbmFsX3N1bW1hcnkgPC0gYXV0aG9yX2Vtb3Rpb25hbF9zdW1tYXJ5KHRvbHN0b3lfd29ya3MpCmBgYAoKYGBge3J9CmRvc3RveWV2c2t5X3dvcmtzIDwtIGxpc3Qod2hpdGVfbmlnaHRzLCBub3Rlc19mcm9tX3VuZGVyZ3JvdW5kLCBnYW1ibGVyLCBjcmltZV9hbmRfcHVuaXNobWVudCwgaWRpb3QsIGJyb3RoZXJzX2thcmFtYXpvdikKbmFtZXMoZG9zdG95ZXZza3lfd29ya3MpIDwtIGMoIldoaXRlIE5pZ2h0cyIsICJOb3RlcyBmcm9tIHRoZSB1bmRlcmdyb3VuZCIsICJHYW1ibGVyIiwgIkNyaW1lIGFuZCBQdW5pc2htZW50IiwgIlRoZSBJZGlvdCIsICJCcm90aGVycyBLYXJhbWF6b3YiKQpkb3N0b3lldnNreV9lbW90aW9uYWxfdmFsZW5jZSA8LSBhdXRob3JfdmFsZW5jZShkb3N0b3lldnNreV93b3JrcykKZG9zdG95ZXZza3lfZW1vdGlvbmFsX3N1bW1hcnkgPC0gYXV0aG9yX2Vtb3Rpb25hbF9zdW1tYXJ5KGRvc3RveWV2c2t5X3dvcmtzKQoKYGBgCkZpcnN0IHdlIGxvb2sgYXQgZW1vdGlvbmFsIHZhbGVuY2UgaW4gdGhlIHdvcmtzIG9mIERvc3RveWV2c2t5LgpgYGB7cn0KZG9zdG95ZXZza3lfZW1vdGlvbmFsX3ZhbGVuY2UgJT4lCmdncGxvdChhZXMoeCA9IGluZGV4LCB5ID0gZW1vdGlvbmFsX3ZhbGVuY2UsIGNvbG9yID0gdGl0bGUpKSArCiAgZ2VvbV9saW5lKCkgKwogIHRoZW1lX3N5dXpoZXQgKyAKICBsYWJzKHk9IkVtb3Rpb25hbCBWYWxlbmNlIiwgeD0iTm9ybWFsaXplZCBOYXJyYXRpdmUgTGVuZ3RoIikKICAKCmBgYApJdCBzZWVtcyB0aGF0IElkaW90IGlzIHF1aXRlIGFuIHVuc3VhbCB3b3JrcyBmb3IgRG9zdG95ZXZza3ksIGl0IGlzIG11Y2ggbW9yZSBwb3NpdGl2ZSB0aGFuIGhpcyBvdGhlciB3b3Jrcy4gV2Ugc2VlIHRoYXQgbW9zdCBvZiB0aGUgd29ya3MgZWl0aGVyIG9zY2lsYXRlIGJldHdlZW4gcG9zaXRpdmUgYW5kIG5lZ2F0aXZlIGVtb3Rpb25hICwgYW5kIGxhcmdseSBuZWdhdGl2ZS4gV2Ugc2VlIGFsc28gdGhhdCBzaGFwZXMgZGlmZmVyIHF1aXRlIHNpbmdpZmljYW50bHkgYmV0d2VlbiBkaWZmZXJlbnQgdGV4dCwgbmQgdGhlcmUgZG9lc24ndCBzZWVtIHRvIGJlIERvc3RveWVza3kgZm9ybXVsYSBmb3IgYSBub3ZlbC4gVG8gZ2V0IGJldHRlciBwZXJzcGVjdGl2ZSBsZXQncyBub3cgdGFrZSBhIGxvb2sgYXQgd29ya3Mgb2YgdGhlIG90aGVyIGdyZWF0IHJ1c3NpYW4gd3JpdGVyIGZyb20gdGhlIDE5dGggY2VudHVyeSAtIExlbyBUb2xzdG95LgoKYGBge3J9CnRvbHN0b3lfZW1vdGlvbmFsX3ZhbGVuY2UgJT4lCmdncGxvdChhZXMoeCA9IGluZGV4LCB5ID0gZW1vdGlvbmFsX3ZhbGVuY2UsIGNvbG9yID0gdGl0bGUpKSArCiAgZ2VvbV9saW5lKCkgKwogIHRoZW1lX3N5dXpoZXQgKyAKICBsYWJzKHk9IkVtb3Rpb25hbCBWYWxlbmNlIiwgeD0iTm9ybWFsaXplZCBOYXJyYXRpdmUgTGVuZ3RoIikKYGBgCk9uZSBjb21tb24gdGhlbWUgb2YgVG9sc3RveSdzIHdvcmtzIGlzIHRoYXQgdGhlIHRoeWUgY29udGFpbmUgbW9yZSBwb3NpdGl2ZSBlbW90aW9ucyBhbmQgaGlzIG1vc3QgZmFtb3VzdCB3b3JrcyAiQW5uYSBLYXJlbmluYSIgYW5kIFdhciBhbmQgUGVhY2UgaGF2ZSB0aGVpciBlbW90aW9uYWwgdmFsZW5jZSBoaWdoZXIgdGhhbiBsYXRlciB3b3JrLgpgYGB7cn0KdG9sc3RveV9lbW90aW9uYWxfdmFsZW5jZVsiYXV0aG9yIl0gPSAiVG9sc3RveSwgTGVvIgpkb3N0b3lldnNreV9lbW90aW9uYWxfdmFsZW5jZVsiYXV0aG9yIl0gPSAiRG9zdG95ZXZza3ksIEZ5b2RvciIKcmJpbmQodG9sc3RveV9lbW90aW9uYWxfdmFsZW5jZSxkb3N0b3lldnNreV9lbW90aW9uYWxfdmFsZW5jZSkgJT4lCmdncGxvdChhZXMoeCA9IGluZGV4LCB5ID0gZW1vdGlvbmFsX3ZhbGVuY2UsIGNvbG9yID0gdGl0bGUsIGxpbmV0eXBlID0gYXV0aG9yKSkgKwogIGdlb21fbGluZSgpICsgCiAgI3RoZW1lX3N5dXpoZXQgKyAKICBsYWJzKHk9IkVtb3Rpb25hbCBWYWxlbmNlIiwgeD0iTm9ybWFsaXplZCBOYXJyYXRpdmUgTGVuZ3RoIikKYGBgCldoZW4gd2UgY29tcGFyZSBib3RoIHdyaXRlcnMgd2Ugc2VlIHRoYXQgVG9sc3RveSB3b3JrcyBhcmUgbXVjaCBzdHJvbmdlciBpbiBwb3N0aXZlIGVtb3Rpb25zIHRoYW4gd29ya3Mgb2YgRG9zdG95ZXZza3kuIFRoZSBJZGlvdCBpcyBxdWl0ZSBvdXRzdGFuZGluZywgY29tcGFyZWQgdG8gb3RoZXIgRG9zdG95ZXZza3kgd29ya3MsIGFuZCBhY3R1YWxseSBpcyBjbG9zZXIgdG8gd29ya3Mgb2YgVG95c3RveSB0aGFuayBvdGhlciB3b3JrcyBvZiBEb3N0b3lldnNreSBpbiB0ZXJtcyBvZiBlbW90aW9uYWwgdmFsZW5jZS4gT25lIGludGVyZXN0aW5nIG9ic2VydmF0aW9uIGlzIHRoYXQgd29ya3Mgd2hpY2ggYXJlIGNvbnNpZGVyZWQgdGhlIGdyZWF0ZXN0IGZvciBib3RoIGF1dGhvcnMgaGF2ZSBhbHNvIGJpZ2dlc3QgY2hhbmdlcyBpbiBlbW90aW9uYWwgdmFsZW5jZS4KYGBge3J9CnRvbHN0b3lfZW1vdGlvbmFsX3ZhbGVuY2VbImF1dGhvciJdIDwtICJUb2xzdG95LCBMZW8iCmRvc3RveWV2c2t5X2Vtb3Rpb25hbF92YWxlbmNlWyJhdXRob3IiXSA8LSAiRG9zdG95ZXZza3ksIEZ5b2RvciIKcmJpbmQodG9sc3RveV9lbW90aW9uYWxfdmFsZW5jZSxkb3N0b3lldnNreV9lbW90aW9uYWxfdmFsZW5jZSkgJT4lIAogIGZpbHRlcih0aXRsZSAlaW4lIGMoIkFubmEgS2FyZW5pbmEiLCAiV2FyIGFuZCBQZWFjZSIsICJUaGUgSWRpb3QiLCAiQnJvdGhlcnMgS2FyYW1hem92IiwgIkNyaW1lIGFuZCBQdW5pc2htZW50IikpICU+JQpnZ3Bsb3QoYWVzKHggPSBpbmRleCwgeSA9IGVtb3Rpb25hbF92YWxlbmNlLCBjb2xvciA9IHRpdGxlLCBsaW5ldHlwZSA9IGF1dGhvcikpICsgZ2VvbV9saW5lKCkKYGBgCiBMZXQncyBsb29rIGF0IHBlcnNwZWNpdGl2ZSBvZiBkaXN0aW5jdCBlbW90aW9ucyBpbiB0aGUgd29ya3M6CiAKYGBge3J9CnJvdy5uYW1lcyhkb3N0b3lldnNreV9lbW90aW9uYWxfc3VtbWFyeSkgPC0gMTo2CmRvc3RveWV2c2t5X2Vtb3Rpb25hbF9zdW1tYXJ5X2RmIDwtIGFzLmRhdGEuZnJhbWUoZG9zdG95ZXZza3lfZW1vdGlvbmFsX3N1bW1hcnkpCmRvc3RveWV2c2t5X2Vtb3Rpb25hbF9zdW1tYXJ5X2RmWyJhdXRob3IiXSA8LSAiRG9zdG95ZXZza3ksIEZ5b2RvciIKCnJvdy5uYW1lcyh0b2xzdG95X2Vtb3Rpb25hbF9zdW1tYXJ5KSA8LSAxOjQKdG9sc3RveV9lbW90aW9uYWxfc3VtbWFyeV9kZiA8LSBhcy5kYXRhLmZyYW1lKHRvbHN0b3lfZW1vdGlvbmFsX3N1bW1hcnkpIAp0b2xzdG95X2Vtb3Rpb25hbF9zdW1tYXJ5X2RmWyJhdXRob3IiXSA8LSAgIlRvbHN0b3ksIExlbyIKCmVtb3Rpb25hbF9zdW1tYXJ5X2RmIDwtIHJiaW5kKGRvc3RveWV2c2t5X2Vtb3Rpb25hbF9zdW1tYXJ5X2RmLCB0b2xzdG95X2Vtb3Rpb25hbF9zdW1tYXJ5X2RmKSAlPiUgZ2F0aGVyKGVtb3Rpb24sIHZhbHVlLCBqb3k6YW5nZXIpIAoKZW1vdGlvbmFsX3N1bW1hcnlfZGZbImVtb3Rpb24iXSA8LSBmY3RfcmVsZXZlbChhc19mYWN0b3IoZW1vdGlvbmFsX3N1bW1hcnlfZGZbLCJlbW90aW9uIl0pLCBjKCJqb3kiLCJ0cnVzdCIsImFudGljaXBhdGlvbiIsInN1cnByaXNlIiwic2FkbmVzcyIsImRpc2d1c3QiLCJmZWFyIiwiYW5nZXIiKSkKYGBgCiAKYGBge3J9CmdncGxvdChlbW90aW9uYWxfc3VtbWFyeV9kZiwgYWVzKHggPSB0aXRsZSwgeSA9IHZhbHVlLCBmaWxsID0gZW1vdGlvbikpICsKICBnZW9tX2NvbChwb3NpdGlvbiA9IHBvc2l0aW9uX2RvZGdlKCkpICsKICBjb29yZF9mbGlwKCkgKwogIHNjYWxlX2NvbG9yX2JyZXdlcigyKSArCiAgCiAgdGhlbWUoYXhpcy50aWNrcz1lbGVtZW50X2JsYW5rKCksIGF4aXMudGV4dC54PWVsZW1lbnRfYmxhbmsoKSkgKwogIGZhY2V0X3dyYXAofmF1dGhvciwgc2NhbGVzID0gImZyZWVfeSIpCmBgYApGaXJzdCB3ZSBub3RpY2UgZm9yIGJvdGggYXV0aG9ycyBpcyB0aGF0IHVuaXZlcnNhbGx5IHN0cm9uZ2VzdCBlbW90aW9uIGFyZSB0cnVzdCBhbmQgYW50aWNpcGF0aW9uLiAgV2l0aCBpbmZvcm1hdGlvbiB3ZSBoYXZlIGl0IGlzIGhhcmQgdG8ganVkZ2UgaWYgdGhpcyBpcyBzb21lIGNoYXJhdGVyaXN0aWMgb2Ygd29yaywgb3IgbWF5YmUgaXQgaXMgY2F1c2VkIGJ5IHNvbWUgZmxhdyBpbiBhbmFseXNpcyBtZXRob2QuIFRvIGV2YWx1dGUgaXQgcHJvcGVybHkgd2Ugc2hvdWxkIGNvbmR1Y3QgcHJvcGVyIGFuYWx5c2lzIG9mIHRoZSBiaWdnZXIgY29ycG9yYSBvZiB3b3JrcyBmcm9tIHRoZSBwZXJpb2QuIFNvbWUgaW1wcmVzc2lvbnMgb25lIGNvdWxkIHRha2UgaXMgdGhhdCBuZWdhdGl2ZSBlbW90aW9ucyBhcmUgbW9yZSBjb21tb24gaW4gd29ya3Mgb2YgRG9zdG95ZXZza3kgdGhhbiBpbiB3cml0aW5nIG9mIFRvbHN0b3kuIEluIENyaW1lIGFuZCBQdW5pc2htZW50IGFuZCBCcm90aGVycyBLYXJhbWF6b3YsIGFuZCBpbiBOb3RlcyBmb20gdGhlIFVuZGVyZ3JvdW5kIGZlYXIgaXMgb25lIG9mIHRoZSBkb21pbmF0aW5nIGVtb3Rpb25zLiBUaGUgSWRpb3Qgc2VlbXMgdG8gYmUgbW9zdCBwb3NpdGl2ZSBvZiBEb3N0b3lldnNreSB3b3JrcyBmcm9tIHRoZSBvbmUgd2UgZXhhbWluZWQuIFdoZW4gZXhhbWluaW5nIHdvcmtzIG9mIFRvbHN0b3kgd2Ugc2VlIHRoYXQgc29tZSBsYXRlciB3b3JrIGxpa2UgTWFzdGVyIGFuZCBNYW4gYW5kIFJlc3VyZWN0aW9uIGNvbnRhaW5zIG1vcmUgbmVnYXRpdmUgZW1vdGlvbnMsIHdoaWxlIGluIGJvdGggQW5uYSBLYXJlbmluYSBhbmQgV2FyIGFuZCBQZWFjZSBqb3kgaXMgb25lIG9mIHRoZSBtb3N0IGNvbW1vbiBzZW50aW1lbnRzLgpTdGlsbCB3ZSBzaG91bGQgdHJlYXQgdGhpcyBhbmFseXNpcyBhcyB0b29sIGZvciBoeXBvdGhlc2lzIGdlbmVyYXRpb24uIAoKClN5dXpoZXQgaXMgZmFudGFzdGljIHRvb2wuIEkgbWFrZXMgc2VudGltZW50IGFuYWx5c2lzIGVhc3kgYW5kIHBsZWFzYW50LiBJIGZvdW5kIGl0IHBhcnRpY3VsYXIgdXNlZnVsIGZvciBleHBsb3JhdG9yeSBhbmFseXNpcyBhbmQgaHlwb3RoZXNpcyBnZW5lcmF0aW9uIG9mIGxvbmdlciB0ZXh0dWFsIGRhdGEuIFN0aWxsIHRoZXJlIGlzIGEgbnVtYmVyIG9mIGh5cGVycGFyYW1ldHJzIHdlIGhhdmUgdG8gdHVuZSB0byB1c2UsIHdlIGhhdmUgdG8gY2hvb3NlIHRoZSByaWdodCBsZXhpY29uIGFuZCBzZW50aW1lbnQgYW5hbHlzaXMgbWV0aG9kIGFuZCBpdCBpcyBub3QgY2xlYXIgd2hpY2ggbWV0aG9kcyBvZiBzbW9vdGhpbmcgd29yayBiZXN0LiBNb3N0IG9mIGV4aXN0aW5nIGJlbmNobWFya3MgZm9yIHNlbnRpbWVudCBhbmFseXNpcyBhcmUgZG9uZSBmb3IgZGlmZmVybnQga2luZHMgb2YgdGV4dHMgLSBlLmcuIG1vdmllIHJldmlld3MgYW5kIHRoZXJlZm9yZSBhcmUgbm90IGFsd2F5cyBhcHBsaWNhYmxlIGZvciBjb3Jwb3JhIG9mIGZpY3Rpb24sIHdoaWNoIG9mdGVuIHVzZXMgdmVyeSBzcGVjaWZpYywgb2xkZXIgbGFuZ3VhZ2UuIFRvIGV2YWx1YXRlIGl0IHByb3Blcmx5IGl0IHdvdWxkIGJlIGdyZWF0IHRvIGhhdmUgYmlnZ2VyLCBzZW50aW1lbnQgYW5ub3RhdGVkIGNvcnBvcmEgb2YgbGl0ZXJhdHVyZS4=